book:([]time:`second$();sym:`$();side:`char$();price:`float$();size:`int$()) 


/create sample data 
s:(),`FDP ;
px:(),5 ;
create:{[n]dict:s!px;sym:n?s;side:n?"BS";    
      price:((+;-)side="B") .'flip(dict sym;.05*n?1+til 10);   
      sample:flip`time`sym`side`price`size! (09:30:00+til n;sym;side;price;100*n?1+til 10)}
             
             
book:create 10 ;
x:create 10;

//structure1:table keyed on sym,side,price
book3key: `sym`side`price xkey book;

//structure2: separate tables keyed on sym,price
bidbook2key:askbook2key:`sym`price xkey book;

//structure3: table keyed on side,price in dict keyed on sym
bookbysym:(1#`) ! enlist `side`price xkey book;

//structure 4
bidbookbysym: askbookbysym:(1#`) ! enlist `price xkey book;


bookfloat: `sym`side`price xkey book;
`bookfloat upsert flip`time`sym`side`price`size! (09:30:00 09:30:01;`FDP`FDP;"BB";4.950000001 4.949999996;100 0) 
\P 0
// about the precise We can learn from q -tips

/sample upd function to populate each structure

updSimple:{[t;x]`book3key upsert x};

updBySide:{[t;x]    
     if[count bid:select from x where side="B";`bidbook2key upsert bid];  
     if[count ask:select from x where side="S";`askbook2key upsert ask];   
    } ;
 
updBySym:{[t;x]
      s:first x`sym;   
      bookbysym[s],:x;    
   } ;
 
updBySymSide:{[t;x]
     s:first x`sym;    
     if[count bid:select from x where side="B";bidbookbysym[s],:bid];      
     if[count ask:select from x where side="S";askbookbysym[s],:ask];
     } ;
 
// test which structure will be quick in upserting


//accessing the order book
//now that the data is being maintained in each of our four structures, it is
/ worthwhile considering some common queries that we might wish to perform, the 
/ most obvious being extracting top-of-book.The following functions all tabke a 
/ single symbol as an argument and return the same result;

/sample functions to extract top-of-book 
getTopOfBook:{[s]   
     b:exec bid:max price from book3key where sym=s,side="B";      
     a:exec ask:min price from book3key where sym=s,side="S";     
     b,a
     } ;
 
getTopOfBookBySide:{[s]         
    b:exec bid:max price from bidbook2key where sym=s;  
    a:exec ask:min price from askbook2key where sym=s;     
    b,a
    } ;
 
getTopOfBookBySym:{[s]      
   b:exec bid:max price from bookbysym[s]where side="B";     
   a:exec ask:min price from bookbysym[s]where side="S";     
   b,a
   } ;

getTopOfBookBySymSide:{[s]   
      b:exec bid:max price from bidbookbysym s;    
      a:exec ask:min price from askbookbysym s;   
      b,a
    } ;
    
getTopOfBookBySymSide2:{[s] `bid`ask!(max key[bidbookbysym s]`price;min key[askbookbysym s]`price)} 
    
/     do[10000;getTopOfBook`FDP]
 
 //get top 2 levels
 
 
 
 /sample functions to extract top 2 levels 
getTop2Book:{[s]      
    b:`bid`bid1!2 sublist desc exec price from book3key where sym=s,side="B";    
    a:`ask`ask1!2 sublist asc exec price from book3key where sym=s,side="S";   
    reverse[b],a
    } ;
getTop2BookBySide:{[s]
         b:`bid`bid1!2 sublist desc exec price from bidbook2key where sym=s; 
         a:`ask`ask1!2 sublist asc exec price from askbook2key where sym=s; 
         reverse[b],a
         }; 
getTop2BookBySym:{[s]          
        b:`bid`bid1!2 sublist desc exec price from bookbysym[s]where side="B";  
        a:`ask`ask1!2 sublist asc exec price from bookbysym[s]where side="S"; 
        reverse[b],a
        };
getTop2BookBySymSide:{[s]  
       b:`bid`bid1!2 sublist desc exec price from bidbookbysym s;    
       a:`ask`ask1!2 sublist asc exec price from askbookbysym s;  
       reverse[b],a
       } ;
/  do[10000;getTop2Book`FDP] 

getTop2BookBySymSide2:{[s]       
        bid:max bids:key[bidbookbysym s]`price;   
        b:`bid1`bid!(max bids where not bids=bid;bid);        
        ask:min asks:key[askbookbysym s]`price;        
        a:`ask`ask1!(ask;min asks where not asks=ask);  
        b,a
        } ;
 
 //business use case
 
/  now let us consider more realistic examples by increasing the number of
/  symbols across a range of one thousand to five thousand increments, and adding twenty 
/  levels of depth on each side.
/  For these example ,it makes sense to apply some attributes to the different structures 
/  to maximize query efficiency. We will not profile the update functions again since we used 
/  the assumption of only ever receiving updates for a single symbol.

/ //conlusion: ultimeately: the decision as to how to store the data will depend on the two factors 
/ identified in this paper:
/ 1.how the data is received by the process maintaining book state 
/ 2.how the data is to be accessed inside the process 
 